/*
 ------------------------------------------------------------------------------
 Copyright (C) 2013 Eternal Games.

 This file is part of the EternalTech source code.

 The EternalTech source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The EternalTech source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the EternalTech source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// cg_load.cpp - assets loading
//


#include "cg_local.h"


/*
 ==============================================================================

 LOADING SCREEN

 ==============================================================================
*/


/*
 ==================
 
 ==================
*/
static void CG_UpdateLoading (const char *string){

	// Bring up the loading GUI
	glqGUI->Activate(cgs.loadingGUI, glqSystem->Milliseconds());

	// Print a message to the console
	G_Printf("...loading %s\n", string);

	// Update the screen and sounds to let the loading GUI refresh.
	// This will also allow the user to abort the loading process.
	etClient->UpdateLoading();
}

/*
 ==================
 
 ==================
*/
void CG_DrawLoading (){

	// If we don't have the loading GUI for any reason, we can't draw anything
	if (!cgs.loadingGUI)
		return;
}


/*
 ==============================================================================

 LEVEL LOADING

 ==============================================================================
*/


/*
 ==================
 
 ==================
*/
static void CG_LoadAssets (){

	char	name[MAX_PATH_LENGTH];
	int		time;
	int		i;

	time = glqSystem->Milliseconds();

	G_Printf("------------ Level Loading ------------\n");
	G_Printf("Loading %s\n", cgs.levelName);

	// Load the clip map
	CG_UpdateLoading("clip map");

	Str_SPrintf(name, sizeof(name), "maps/%s.bsp", cgs.levelName);
	glqCollision->LoadMap(name);

	// Load the world map
	CG_UpdateLoading("world map");

	Str_SPrintf(name, sizeof(name), "maps/%s.bsp", cgs.levelName);
	glqRenderer->LoadMap(name);

	// Load the post-process effects
	CG_UpdateLoading("post-process effects");

	Str_SPrintf(name, sizeof(name), "maps/%s.postProcess", cgs.levelName);
	glqRenderer->LoadPostProcess(name);

	// Load the reverb effects
	CG_UpdateLoading("reverb effects");

	// Load the models
	CG_UpdateLoading("models");

	for (i = 1; i < MAX_GAME_MODELS; i++){
		if (!cgs.configStrings[CS_MODELS + i])
			break;

		cgs.gameModels[i] = glqRenderer->RegisterModel(cgs.configStrings[CS_MODELS + i]);
	}

	// Load the materials
	CG_UpdateLoading("materials");

	cgs.whiteMaterial = glqRenderer->RegisterMaterialNoMip("white");

	cgs.pauseMaterial = glqRenderer->RegisterMaterialNoMip("pause");

	for (i = 0; i < 11; i++){
		if (i != 10){
			cgs.sbNumberMaterials[0][i] = glqRenderer->RegisterMaterialNoMip(Str_VarArgs("num_%i", i));
			cgs.sbNumberMaterials[1][i] = glqRenderer->RegisterMaterialNoMip(Str_VarArgs("anum_%i", i));
		}
		else {
			cgs.sbNumberMaterials[0][i] = glqRenderer->RegisterMaterialNoMip("num_minus");
			cgs.sbNumberMaterials[1][i] = glqRenderer->RegisterMaterialNoMip("anum_minus");
		}
	}

	cgs.sbColonMaterial = glqRenderer->RegisterMaterialNoMip("num_colon");
	cgs.sbSlashMaterial = glqRenderer->RegisterMaterialNoMip("num_slash");

	cgs.sbWeaponMaterials[0][0] = glqRenderer->RegisterMaterialNoMip("inv_shotgun");
	cgs.sbWeaponMaterials[0][1] = glqRenderer->RegisterMaterialNoMip("inv_sshotgun");
	cgs.sbWeaponMaterials[0][2] = glqRenderer->RegisterMaterialNoMip("inv_nailgun");
	cgs.sbWeaponMaterials[0][3] = glqRenderer->RegisterMaterialNoMip("inv_snailgun");
	cgs.sbWeaponMaterials[0][4] = glqRenderer->RegisterMaterialNoMip("inv_rlaunch");
	cgs.sbWeaponMaterials[0][5] = glqRenderer->RegisterMaterialNoMip("inv_srlaunch");
	cgs.sbWeaponMaterials[0][6] = glqRenderer->RegisterMaterialNoMip("inv_lightng");
	cgs.sbWeaponMaterials[1][0] = glqRenderer->RegisterMaterialNoMip("inv2_shotgun");
	cgs.sbWeaponMaterials[1][1] = glqRenderer->RegisterMaterialNoMip("inv2_sshotgun");
	cgs.sbWeaponMaterials[1][2] = glqRenderer->RegisterMaterialNoMip("inv2_nailgun");
	cgs.sbWeaponMaterials[1][3] = glqRenderer->RegisterMaterialNoMip("inv2_snailgun");
	cgs.sbWeaponMaterials[1][4] = glqRenderer->RegisterMaterialNoMip("inv2_rlaunch");
	cgs.sbWeaponMaterials[1][5] = glqRenderer->RegisterMaterialNoMip("inv2_srlaunch");
	cgs.sbWeaponMaterials[1][6] = glqRenderer->RegisterMaterialNoMip("inv2_lightng");

	for (i = 0; i < 5; i++){
		cgs.sbWeaponMaterials[2+i][0] = glqRenderer->RegisterMaterialNoMip(Str_VarArgs("inva%i_shotgun", i+1));
		cgs.sbWeaponMaterials[2+i][1] = glqRenderer->RegisterMaterialNoMip(Str_VarArgs("inva%i_sshotgun", i+1));
		cgs.sbWeaponMaterials[2+i][2] = glqRenderer->RegisterMaterialNoMip(Str_VarArgs("inva%i_nailgun", i+1));
		cgs.sbWeaponMaterials[2+i][3] = glqRenderer->RegisterMaterialNoMip(Str_VarArgs("inva%i_snailgun", i+1));
		cgs.sbWeaponMaterials[2+i][4] = glqRenderer->RegisterMaterialNoMip(Str_VarArgs("inva%i_rlaunch", i+1));
		cgs.sbWeaponMaterials[2+i][5] = glqRenderer->RegisterMaterialNoMip(Str_VarArgs("inva%i_srlaunch", i+1));
		cgs.sbWeaponMaterials[2+i][6] = glqRenderer->RegisterMaterialNoMip(Str_VarArgs("inva%i_lightng", i+1));
	}

	cgs.sbAmmoMaterials[0] = glqRenderer->RegisterMaterialNoMip("sb_shells");
	cgs.sbAmmoMaterials[1] = glqRenderer->RegisterMaterialNoMip("sb_nails");
	cgs.sbAmmoMaterials[2] = glqRenderer->RegisterMaterialNoMip("sb_rocket");
	cgs.sbAmmoMaterials[3] = glqRenderer->RegisterMaterialNoMip("sb_cells");

	cgs.sbArmorMaterials[0] = glqRenderer->RegisterMaterialNoMip("sb_armor1");
	cgs.sbArmorMaterials[1] = glqRenderer->RegisterMaterialNoMip("sb_armor2");
	cgs.sbArmorMaterials[2] = glqRenderer->RegisterMaterialNoMip("sb_armor3");

	cgs.sbItemMaterials[0] = glqRenderer->RegisterMaterialNoMip("sb_key1");
	cgs.sbItemMaterials[1] = glqRenderer->RegisterMaterialNoMip("sb_key2");
	cgs.sbItemMaterials[2] = glqRenderer->RegisterMaterialNoMip("sb_invis");
	cgs.sbItemMaterials[3] = glqRenderer->RegisterMaterialNoMip("sb_invuln");
	cgs.sbItemMaterials[4] = glqRenderer->RegisterMaterialNoMip("sb_suit");
	cgs.sbItemMaterials[5] = glqRenderer->RegisterMaterialNoMip("sb_quad");

	cgs.sbSigilMaterials[0] = glqRenderer->RegisterMaterialNoMip("sb_sigil1");
	cgs.sbSigilMaterials[1] = glqRenderer->RegisterMaterialNoMip("sb_sigil2");
	cgs.sbSigilMaterials[2] = glqRenderer->RegisterMaterialNoMip("sb_sigil3");
	cgs.sbSigilMaterials[3] = glqRenderer->RegisterMaterialNoMip("sb_sigil4");

	cgs.sbFaceMaterials[4][0] = glqRenderer->RegisterMaterialNoMip("face1");
	cgs.sbFaceMaterials[4][1] = glqRenderer->RegisterMaterialNoMip("face_p1");
	cgs.sbFaceMaterials[3][0] = glqRenderer->RegisterMaterialNoMip("face2");
	cgs.sbFaceMaterials[3][1] = glqRenderer->RegisterMaterialNoMip("face_p2");
	cgs.sbFaceMaterials[2][0] = glqRenderer->RegisterMaterialNoMip("face3");
	cgs.sbFaceMaterials[2][1] = glqRenderer->RegisterMaterialNoMip("face_p3");
	cgs.sbFaceMaterials[1][0] = glqRenderer->RegisterMaterialNoMip("face4");
	cgs.sbFaceMaterials[1][1] = glqRenderer->RegisterMaterialNoMip("face_p4");
	cgs.sbFaceMaterials[0][0] = glqRenderer->RegisterMaterialNoMip("face5");
	cgs.sbFaceMaterials[0][1] = glqRenderer->RegisterMaterialNoMip("face_p5");

	cgs.sbFaceInvisibleMaterial = glqRenderer->RegisterMaterialNoMip("face_invis");
	cgs.sbFaceInvulnerableMaterials[0] = glqRenderer->RegisterMaterialNoMip("face_invul2");
	cgs.sbFaceInvulnerableMaterials[1] = glqRenderer->RegisterMaterialNoMip("face_inv2");
	cgs.sbFaceQuadMaterial = glqRenderer->RegisterMaterialNoMip("face_quad");

	cgs.sbBarMaterial = glqRenderer->RegisterMaterialNoMip("sbar");
	cgs.sbItemBarMaterial = glqRenderer->RegisterMaterialNoMip("ibar");
	cgs.sbScoreboardMaterial = glqRenderer->RegisterMaterialNoMip("scorebar");

	cgs.sbDiscMaterial = glqRenderer->RegisterMaterialNoMip("disc");

	for (i = 0; i < NUM_CROSSHAIRS; i++)
		cgs.crosshairMaterials[i] = glqRenderer->RegisterMaterialNoMip(Str_VarArgs("gfx/crosshairs/ch%i", i+1));

	for (i = 1; i < MAX_GAME_MATERIALS; i++){
		if (!cgs.configStrings[CS_MATERIALS + i])
			break;

		if (Str_ICompareChars(cgs.configStrings[CS_MATERIALS + i], "lights/", 7))
			cgs.gameMaterials[i] = glqRenderer->RegisterMaterial(cgs.configStrings[CS_MATERIALS + i]);
		else
			cgs.gameMaterials[i] = glqRenderer->RegisterMaterialLight(cgs.configStrings[CS_MATERIALS + i]);
	}

	// Load the sound shaders
	CG_UpdateLoading("sound shaders");

	for (i = 1; i < MAX_GAME_SOUND_SHADERS; i++){
		if (!cgs.configStrings[CS_SOUND_SHADERS + i])
			break;

		cgs.gameSoundShaders[i] = glqSound->RegisterSoundShader(cgs.configStrings[CS_SOUND_SHADERS + i]);
	}

	// Load the GUIs
	CG_UpdateLoading("GUIs");

	G_Printf("---------------------------------------\n");
	G_Printf("Level loaded in %.2f seconds\n", MS2SEC(glqSystem->Milliseconds() - time));
}

/*
 ==================
 CG_PrecacheLights

 FIXME: this seems to crash because renderLights is not filled in
 ==================
*/
static void CG_PrecacheLights (){

	entityState_t	*baseline;
	light_t			*light;
	renderLight_t	*renderLight, renderLights[MAX_ENTITIES];
	int				numRenderLights = 0;
	int				i;

	// Grab all the lights
	for (i = MAX_CLIENTS; i < MAX_ENTITIES; i++){
		baseline = &cgs.baselines[i];

		if (baseline->type != ET_LIGHT)
			continue;

		light = (light_t *)baseline->buffer;

		// Set up a render light
		renderLight = &renderLights[numRenderLights++];

		renderLight->type = (rlType_t)light->type;
		renderLight->lightNum = baseline->number;
		renderLight->origin = baseline->origin.base;
		renderLight->center = light->center;
		renderLight->axis = baseline->angles.base.ToMat3();
		renderLight->radius = light->radius;
		renderLight->xMin = light->xMin;
		renderLight->xMax = light->xMax;
		renderLight->yMin = light->yMin;
		renderLight->yMax = light->yMax;
		renderLight->zNear = light->zNear;
		renderLight->zFar = light->zFar;
		renderLight->noShadows = light->noShadows;
		renderLight->shadowBias = light->shadowBias;
		renderLight->shadowSlopeScaleBias = light->shadowSlopeScaleBias;
		renderLight->shadowSoftness = light->shadowSoftness;
		renderLight->fogDistance = light->fogDistance;
		renderLight->fogHeight = light->fogHeight;
		renderLight->volumeIntensity = light->volumeIntensity;
		renderLight->volumeShadows = light->volumeShadows;
		renderLight->volumeInteractions = light->volumeInteractions;
		renderLight->detailLevel = light->detailLevel;
		renderLight->allowInView = VIEW_ALL;
		renderLight->material = cgs.gameMaterials[light->material];
		renderLight->materialParms[0] = light->materialParms[0];
		renderLight->materialParms[1] = light->materialParms[1];
		renderLight->materialParms[2] = light->materialParms[2];
		renderLight->materialParms[3] = light->materialParms[3];
		renderLight->materialParms[4] = light->materialParms[4];
		renderLight->materialParms[5] = light->materialParms[5];
		renderLight->materialParms[6] = light->materialParms[6];
		renderLight->materialParms[7] = light->materialParms[7];
		renderLight->soundEmitterHandle = 0;
	}

	// Generate lists of static shadows and interactions and precache all the
	// lights
	glqRenderer->PrecacheLights(cgs.scene, numRenderLights, renderLights);
}

/*
 ==================
 CG_LoadLevel
 ==================
*/
void CG_LoadLevel (){

	cgs.loading = true;

	// Allocate the primary scene
	cgs.scene = glqRenderer->AllocScene(true);

	// Load the loading GUI
	cgs.loadingGUI = glqGUI->Register("loading");

	// Parse the initial values
	CG_ParseConfig();

	// Load the assets
	CG_LoadAssets();

	// Precache all the lights
//	CG_PrecacheLights();

	// We have loaded the level
	cgs.loading = false;
}

/*
 ==================
 CG_FreeLevel
 ==================
*/
void CG_FreeLevel (){

	// Clear all the entities
	CG_ClearEntities();

	// Clear the local player entity
	CG_ClearPlayerEntity();

	// Clear the testing utilities
	CG_ClearTestModel();
	CG_ClearTestSound();
	CG_ClearTestPostProcess();

	// Clear all the active sound emitters
	glqSound->ClearAllSoundEmitters();

	// Stop music
	glqSound->StopMusic();

	// Free the primary scene
	if (cgs.scene){
		glqRenderer->FreeScene(cgs.scene);
		cgs.scene = NULL;
	}
}